package com.rtsapp.server.benchmark.runner;

import com.rtsapp.server.benchmark.ITestCaseConfig;
import com.rtsapp.server.benchmark.ITestRunner;
import com.rtsapp.server.benchmark.ITestRunnerListener;
import com.rtsapp.server.benchmark.cases.cmd.CommandCaseHandler;
import com.rtsapp.server.network.protocol.crypto.client.ClientRSAHandshakeKey;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import com.rtsapp.server.logger.Logger;

import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * Created by admin on 15-9-15.
 */
public class TestRunner implements ITestRunner {

    private static final Logger LOGGER = com.rtsapp.server.logger.LoggerFactory.getLogger(TestRunner.class);

    /**
     * 连接信息
     */
    private final ConnInfo cfg;
    /**
     * 要执行的一组测试配置文件
     */
    private final ITestCaseConfig caseConfig[];
    /**
     * 自定义的命令handler
     */
    private final ICommandCaseHandlerFactory commandCaseHandlerFactory;

    /**
     * 服务器地址
     */
    private final SocketAddress remotePeer;

    /**
     * 事件循环
     */
    private final EventLoopGroup eventLoop;

    /**
     * 测试的监听器
     */
    private final ITestRunnerListener listener;

    private final ClientRSAHandshakeKey keyRSA;

    /**
     * 所有存活的测试会话的数量
     */
    private AtomicInteger sessionCount;


    public TestRunner(ConnInfo cfg, ITestCaseConfig caseConfig[], Class<? extends CommandCaseHandler> commandHandlerClz, ITestRunnerListener listener,  ClientRSAHandshakeKey keyRSA ) {
        this.cfg = cfg;
        this.caseConfig = caseConfig;
        this.commandCaseHandlerFactory = new CommandCaseHandlerFactory( commandHandlerClz );
        this.listener = listener;

        this.remotePeer = new InetSocketAddress(cfg.getIp(), cfg.getPort());

        this.eventLoop = new NioEventLoopGroup(cfg.getThreadNum());

        this.sessionCount = new AtomicInteger(cfg.getConnNum());

        this.keyRSA = keyRSA;

        printTestInfo();
    }

    public TestRunner(ConnInfo cfg, ITestCaseConfig caseConfig[], Class<? extends CommandCaseHandler> commandHandlerClz, ITestRunnerListener listener ){
        this( cfg, caseConfig, commandHandlerClz, listener, null );
    }

    private void printTestInfo(  ){
        LOGGER.info( "========本次测试基本信息=========" );

        int cfgCount = caseConfig.length;
        int totalCaseCount = 0;
        long executeTimeMills = 0;
        for( int i = 0; i < caseConfig.length; i++ ){
            totalCaseCount += caseConfig[i].getCaseCount();
            executeTimeMills += caseConfig[i].getExecuteTimeMills();
        }



        LOGGER.info( "测试用例:" );
        LOGGER.info( "共{}组测试文件, 累计用例数量:{}, 预计总耗时:{}毫秒, 共{}分{}秒 " , cfgCount, totalCaseCount, executeTimeMills, (executeTimeMills / 1000 / 60) , (executeTimeMills / 1000 % 60)  );
        LOGGER.info( "连接信息:" );
        LOGGER.info( "连接IP:{} 端口:{}",cfg.getIp(), cfg.getPort() );
        LOGGER.info( "并发连接数:{}", cfg.getConnNum() );
        LOGGER.info( "总线程数:{}", cfg.getThreadNum() );
        LOGGER.info( "========本次测试基本信息=========" );
        LOGGER.info("");

    }

    public void start() {


        // 创建好所有的测试会话
        TestSession[] allSessions = new TestSession[cfg.getConnNum()];

        long nanoInterval = cfg.getConnStartTime() * 1000L / cfg.getConnNum();
        for (int i = 1; i <= cfg.getConnNum(); i++) {

            long delay = nanoInterval * i;

            TestSession session = new TestSession(this, listener, eventLoop, i, caseConfig, remotePeer, delay);

            allSessions[i - 1] = session;
        }


        //启动测试
        LOGGER.info("测试环境准备完毕, 所有测试开始启动");
        for (TestSession session : allSessions) {
            listener.onTestStart(session.getSessionId(), session.getContext());
            session.start();
        }

    }


    void onSessionClose(TestSession session) {

        int count = sessionCount.decrementAndGet();

        if (count <= 0) {

            LOGGER.info("所有的任务执行完毕, 等待输出测试报告");

            listener.onTestComplete();
            //执行完毕后，关闭测试程序，
            System.exit(0);
        }

    }

    public ClientRSAHandshakeKey getKeyRSA(){
        return this.keyRSA;
    }

    public ICommandCaseHandlerFactory getCommandCaseHandlerFactory() {
        return commandCaseHandlerFactory;
    }

    private static class CommandCaseHandlerFactory implements ICommandCaseHandlerFactory {

        private final Class<? extends CommandCaseHandler> commandHandlerClz;

        public CommandCaseHandlerFactory(Class<? extends CommandCaseHandler> commandHandlerClz) {
            this.commandHandlerClz = commandHandlerClz;
        }

        public CommandCaseHandler createCommandHandler() {

            try {
                return commandHandlerClz.newInstance();
            } catch (InstantiationException e) {
                LOGGER.error("createCommandHandler 失败", e);
                throw new RuntimeException("createCommandHandler 失败");
            } catch (IllegalAccessException e) {
                LOGGER.error("createCommandHandler 失败", e);
                throw new RuntimeException("createCommandHandler 失败");
            }
        }

    }

}
